from handler.HandlerBase import HandlerBase
import pyttsx3
import logging
from multiprocessing import Process


class Voice(HandlerBase):
	def __init__(self, content):
		self.engine = pyttsx3.init()
		voices = self.engine.getProperty('voices')
		self._processes = []

		actors = content['actors']
		self._say_rate = self._get_number(content, 'say_rate', 190)
		self._say_volume = self._get_number(content, 'say_volume', 0.7)
		self._shout_rate = self._get_number(content, 'shout_rate', 260)
		self._shout_volume = self._get_number(content, 'shout_volume', 1.0)
		self._queue = int(self._get_number(content, 'queue', 5))

		self._voice_by_actor = {}
		for actor in actors:
			voices_candidates = [voice for voice in voices if actor in voice.name]
			if len(voices_candidates) == 0:
				logging.info('actor ' + actor + ' voice not installed')
				continue
			self._voice_by_actor[actor] = voices_candidates[0]

		if len(self._voice_by_actor) == 0:
			logging.error('no voices found to match the actors ' + str(actors))

	def _get_number(self, content, name, default):
		content_value = content.get(name)
		if content_value is None:
			return default
		else:
			return float(content_value)

	def change_state(self, from_state, to_state):
		self._remove_dead_processes()

		if to_state is None:
			return

		if len(self._processes) >= self._queue:
			return

		is_shout = False
		actor = ''
		voice = None

		if to_state.startswith('!'):
			is_shout = True
		elif to_state.startswith('.'):
			is_shout = False

		state_split = to_state.split(':')
		actor = ''.join(state_split[0][1:])
		voice = self._voice_by_actor.get(actor)
		text = state_split[1]

		if voice is None:
			return

		volume = self._say_volume
		rate = self._say_rate
		if is_shout is True:
			volume = self._shout_volume
			rate = self._shout_rate
		process = Process(target=_express, args=(voice.id, text, volume, rate))
		process.start()

		self._processes.append(process)

	def _remove_dead_processes(self):
		dead_processes = [process for process in self._processes if process.is_alive() is False]

		for process in dead_processes:
			self._processes.remove(process)

	def close(self):
		for process in self._processes:
			process.terminate()


def _express(voice_id, text, volume, rate):
	engine = pyttsx3.init()
	engine.setProperty('voice', voice_id)
	engine.setProperty('volume', volume)
	engine.setProperty('rate', rate)
	engine.say(text)
	engine.runAndWait()
